package io.gitee.zhangbinhub.acp.boot.component

import io.gitee.zhangbinhub.acp.boot.base.BaseSpringBootScheduledAsyncTask
import io.gitee.zhangbinhub.acp.boot.conf.AcpScheduleConfiguration
import io.gitee.zhangbinhub.acp.boot.log.LogAdapter
import io.gitee.zhangbinhub.acp.core.common.CommonTools
import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler
import org.springframework.scheduling.support.CronTrigger
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ScheduledFuture

/**
 * 定时任务处理器
 *
 * @since JDK 17
 */
class AcpTimerTaskSchedulerCtrl(
    private val logAdapter: LogAdapter,
    private val taskSchedulingProperties: TaskSchedulingProperties,
    private val acpScheduleConfiguration: AcpScheduleConfiguration,
    private val baseSpringBootScheduledTaskMap: Map<String, BaseSpringBootScheduledAsyncTask>?
) {
    private var threadPoolTaskScheduler: ThreadPoolTaskScheduler? = null
    private val scheduledTaskMap = ConcurrentHashMap<String, BaseSpringBootScheduledAsyncTask>()
    private val futureMap = ConcurrentHashMap<String, ScheduledFuture<*>>()
    private fun initSchedule(mayInterruptIfRunning: Boolean) {
        stopSchedule(mayInterruptIfRunning)
        threadPoolTaskScheduler = ThreadPoolTaskScheduler()
        threadPoolTaskScheduler!!.poolSize = taskSchedulingProperties.pool.size
        threadPoolTaskScheduler!!.threadNamePrefix = taskSchedulingProperties.threadNamePrefix
        threadPoolTaskScheduler!!.initialize()
    }

    /**
     * 启动定时任务
     */
    @Throws(InterruptedException::class)
    fun reStartSchedule(mayInterruptIfRunning: Boolean) {
        initSchedule(mayInterruptIfRunning)
        baseSpringBootScheduledTaskMap?.forEach { (key, scheduledTask) ->
            val cronMap = acpScheduleConfiguration.cron
            if (cronMap.isNotEmpty() && cronMap.containsKey(key) && !CommonTools.isNullStr(cronMap[key]) && !"none".equals(
                    cronMap[key],
                    ignoreCase = true
                )
            ) {
                cronMap[key]?.apply {
                    scheduledTaskMap[key] = scheduledTask
                    threadPoolTaskScheduler!!.schedule({ scheduledTask.executeScheduledTask() }, CronTrigger(this))
                        ?.let {
                            futureMap[key] = it
                            logAdapter.info("start scheduled task：" + scheduledTask.taskName + " 【" + this + "】 【" + scheduledTask.javaClass.canonicalName + "】")
                        }
                }
            }
        }
    }

    /**
     * 停止定时任务
     */
    @Throws(InterruptedException::class)
    fun stopSchedule(mayInterruptIfRunning: Boolean) {
        val iterator = scheduledTaskMap.entries.iterator()
        while (iterator.hasNext()) {
            val entry = iterator.next()
            val key = entry.key
            val scheduledTask = entry.value
            val future = futureMap.remove(key)
            while (!scheduledTask.waiting) {
                Thread.sleep(3000)
            }
            future?.cancel(mayInterruptIfRunning)
            logAdapter.info("stop scheduled task：" + scheduledTask.taskName + " 【" + scheduledTask.javaClass.canonicalName + "】")
            iterator.remove()
        }
        threadPoolTaskScheduler?.destroy()
        threadPoolTaskScheduler = null
    }
}
